import * as crypto from 'crypto'
import { HttpService } from '@nestjs/axios'
import { Injectable } from '@nestjs/common'
import { lastValueFrom } from 'rxjs'
import { quickApiUrl, smsApiUrl, smsConfig } from '@/config/sms.config'
/**
 * 文档地址：http://sdkadmin.ilogin.com.cn/docs/index/aid/999#catlog8
 */

export interface HttpRequestOptions {
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'get' | 'post' | 'put' | 'delete'
  url: string
  // 带在 body 中
  params?: Record<string, any>
  // 带在 url 中
  query?: Record<string, any>
}

export interface ISmsResponse<T = any> {
  status: boolean
  data?: T
  message: string
}

@Injectable()
export class SmsService {
  // ? private 函数：只能在当前类内部被访问和调用，没写默认是 public
  /**
   * 接口地址
   */
  private readonly smsApiUrl = smsApiUrl
  private readonly quickApiUrl = quickApiUrl
  /**
   * 配置
   */
  private readonly smsConfig = smsConfig
  /**
   * 生成签名
   */
  private readonly generateSign = (params: Record<string, any>): string => {
    // 过滤空值
    const validParams = { ...params }
    Object.keys(validParams).forEach((key) => {
      if (validParams[key] === undefined || validParams[key] === null) {
        delete validParams[key]
      }
    })

    // 按key升序排序
    const sortedKeys = Object.keys(validParams).sort()

    // 拼接key=val&格式
    let signStr = ''
    sortedKeys.forEach((key) => {
      signStr += `${key}=${validParams[key]}&`
    })

    // 拼接openKey并生成MD5
    signStr += this.smsConfig.openKey
    return crypto.createHash('md5').update(signStr, 'utf8').digest('hex')
  }

  private async request(options: HttpRequestOptions): Promise<ISmsResponse> {
    const { method, url, query, params } = options

    /** 构建最终 URL (带 query 参数) */
    const querySearch = new URLSearchParams({ ...query, raw: 'true' })
    const resultUrl = `${url}?${querySearch.toString()}`

    const data = {
      ...params,
      openId: this.smsConfig.openId,
      productCode: this.smsConfig.productCode,
    }
    const sign = this.generateSign(data)
    const body = {
      ...data,
      sign,
    }

    // （Nest的HttpService返回Observable，需转换为Promise）
    const response = await lastValueFrom(
      this.httpService.request({
        method,
        data: body,
        url: resultUrl,
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
      }),
    )

    return response.data
  }

  constructor(private httpService: HttpService) {}

  /**
   * 发送短信验证码
   */
  async sendCodeByPhone({ phone, uid, sendType = 1 }: { phone: string, uid?: string, sendType?: number }) {
    // 构建请求参数（必传参数+选传参数）
    const url = `${this.smsApiUrl}/webOpen/sendCodeByPhone`
    const params = {
      phone,
      /** 1 手机验证登录 2 绑定手机 3 解绑手机 4 找回密码 */
      sendType,
      /** 用户UID，sendType不为 1 时必传 */
      ...(uid && { uid }),
    }

    // 发送POST请求（Nest的HttpService返回Observable，需转换为Promise）
    const response = await this.request({ url, method: 'post', params })
    return response
  }

  /**
   * 手机号码登录
   */
  async userLoginByPhone({ phone, code }: { phone: string, code: string }) {
    const url = `${this.smsApiUrl}/webOpen/loginByPhone`
    const params = {
      phone,
      code,
    }

    const response = await this.request({ url, method: 'post', params })
    return response as unknown as ISmsResponse<ExpressPlayerUser>
  }

  /**
   * 注册
   */
  async userRegister({ phone, code }: { phone: string, code: string }) {
    const url = `${this.smsApiUrl}/webOpen/upassportReg`
    const params = {
      phone,
      code,
      username: phone,
      password: Math.random().toString(36).substring(2, 8),
    }

    const response = await this.request({ url, method: 'post', params })
    return response as unknown as ISmsResponse<ExpressPlayerUser>
  }

  /**
   * 获取用户信息
   */
  async getUserInfoByPhone({ phone, code }: { phone: string, code: string }) {
    const url = `${this.smsApiUrl}/webOpen/queryUser`
    const params = {
      phone,
      code,
    }

    const response = await this.request({ url, method: 'post', params })
    const { lastLoginTime, maxRoleLevel } = await this.getGameUserInfoByUid({ uid: response.data.uid })

    response.data['lastLoginTime'] = lastLoginTime
    response.data['maxRoleLevel'] = maxRoleLevel
    return response
  }

  /**
   * 获取用户绑定的游戏信息
   */
  async getGameUserInfoByUid({ uid }: { uid: string }) {
    const lastLoginResponse = await this.request({
      url: `${this.quickApiUrl}/query_login`,
      method: 'get',
      query: {
        uid,
      },
    })

    const maxRoleLevelResponse = await this.request({
      url: `${this.quickApiUrl}/query_level`,
      method: 'get',
      query: {
        uid,
      },
    })

    return {
      lastLoginTime: (lastLoginResponse as unknown as { last_login: number })?.last_login || null,
      maxRoleLevel: (maxRoleLevelResponse as unknown as { max_level: number })?.max_level || null,
    }
  }
}
